﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TetrisV1._0
{
    public partial class Form1 : Form
    {
        private int [,] currentBrick=new int[4,4];//当前的方块 序号 形状
        private int currentBrickNum;//当前的方块序号（哪种方块）
        private int currentBrickDirec;//该序号的方块的方向
        private int currentX;//当前方块的位置
        private int currentY;//当前方块的位置

        private int nextBrickNum;//下一个方块的序号
        private int nextBrickDirec;//下一个该序号的方块的方向
        private Image backgroundImage;//得到与panel相同大小的背景图片
        private Random random=new Random();
        private int score;

        //定义四维数组Bricks[m,n,y,x]
        //m：当前方块的序号 n：当前方块的方向 y：当前方块所处的行数 x：当前方块所处的列数
        private int[,,,] Bricks =
        {
            //第一种方块
            {
                {
                    {1,0,0,0},
                    {1,0,0,0},
                    {1,0,0,0},
                    {1,0,0,0}
                },
                {
                    {1,1,1,1},
                    {0,0,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
                {
                    {1,0,0,0},
                    {1,0,0,0},
                    {1,0,0,0},
                    {1,0,0,0}
                },
                {
                    {1,1,1,1},
                    {0,0,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
            },
            //第二种方块
            {
                {
                    {1,1,0,0},
                    {1,1,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
                {
                    {1,1,0,0},
                    {1,1,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
                {
                    {1,1,0,0},
                    {1,1,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
                {
                    {1,1,0,0},
                    {1,1,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
            },
            //第三种方块
            {
                {
                    {1,0,0,0},
                    {1,1,0,0},
                    {0,1,0,0},
                    {0,0,0,0}
                },
                {
                    {0,1,1,0},
                    {1,1,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
                {
                    {1,0,0,0},
                    {1,1,0,0},
                    {0,1,0,0},
                    {0,0,0,0}
                },
                {
                    {0,1,1,0},
                    {1,1,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
            },
            //第四种方块
            {
                {
                    {1,1,0,0},
                    {0,1,0,0},
                    {0,1,0,0},
                    {0,0,0,0}
                },
                {
                    {0,0,1,0},
                    {1,1,1,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
                {
                    {1,0,0,0},
                    {1,0,0,0},
                    {1,1,0,0},
                    {0,0,0,0}
                },
                {
                    {1,1,1,0},
                    {1,0,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
                },
            },
        };

        //定义20*12的背景数组
        private int[,] Background =
        {
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0},
        };
        public Form1()
        {
            InitializeComponent();
        }

        //将panel作为游戏背景板
        private void Form1_Load(object sender, EventArgs e)
        {
            //得到与panel相同大小的背景图片
            backgroundImage = new Bitmap(panel1.Width, panel1.Height);
            score = 0;
        }

        //产生方块
        private void CreateBricks()
        {
            currentBrickNum = nextBrickNum;
            currentBrickDirec = nextBrickDirec;

            nextBrickNum = random.Next(0, 4);
            nextBrickDirec = random.Next(0, 4);

            for(int y=0;y<4;y++)
            {
                for(int x=0;x<4;x++)
                {
                    currentBrick[y, x] = Bricks[currentBrickNum, currentBrickDirec, y, x];
                }
            }
            //方块出现的位置 （7，0）
            currentX = 7;
            currentY = 0;

            //计时器开启
            timer1.Start();
        }
        //随机获取颜色
        public Color GetRandomColor()
        {
            Random RandomNum_First = new Random((int)DateTime.Now.Ticks);
            //  对于C#的随机数，没什么好说的
            System.Threading.Thread.Sleep(RandomNum_First.Next(50));
            Random RandomNum_Sencond = new Random((int)DateTime.Now.Ticks);
            //  为了在白色背景上显示，尽量生成深色
            int int_Red = RandomNum_First.Next(256);
            int int_Green = RandomNum_Sencond.Next(256);
            int int_Blue = (int_Red + int_Green > 400) ? 0 : 400 - int_Red - int_Green;
            int_Blue = (int_Blue > 255) ? 255 : int_Blue;
            return Color.FromArgb(int_Red, int_Green, int_Blue);//.Name
        }
        //画出当前下落的方块和已经下落的方块
        private void DrawCurrentBrick()
        {
            Color randomColor=GetRandomColor();
            //创建窗体画布
            Graphics g = Graphics.FromImage(backgroundImage);

            //清除以前画的图形
            g.Clear(this.panel1.BackColor);

            //画出已经落下的方块
            for (int bgy = 0; bgy < 20; bgy++)
            {
                for (int bgx = 0; bgx < 14; bgx++)
                {
                    if (Background[bgy, bgx] == 1)
                    {
                        //定义方块每一个小单元的边长为20
                        g.FillRectangle(new SolidBrush(randomColor), bgx * 20, bgy * 20, 20, 20);//Color.DimGray
                        g.DrawRectangle(new Pen(Color.Black, 1), bgx * 20, bgy * 20, 20, 20);
                    }
                }
            }

            //绘制当前正在下落的方块  
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    if (currentBrick[y, x] == 1)
                    {
                        //定义方块每一个小单元的边长为20
                        g.FillRectangle(new SolidBrush(Color.DimGray), (x + currentX) * 20, (y + currentY) * 20, 20, 20);
                        g.DrawRectangle(new Pen(Color.Gainsboro, 1), (x + currentX) * 20, (y + currentY) * 20, 20, 20);
                    }
                }
            }

            //获取面板的画布
            Graphics gg = panel1.CreateGraphics();
            gg.DrawImage(backgroundImage, 0, 0);
        }

        //使方块下落
        private void FallBrick()
        {
            //判断是否可以下落
            if(CheckFallBrick())
            {
                currentY++;
            }
            else
            {
                //如果方块已经达到最上方
                if (currentY == 0)
                {
                    timer1.Stop();
                    MessageBox.Show("游戏结束！");
                    return;
                }

                //下落完成，修改背景数组
                for(int y=0;y<4;y++)
                {
                    for(int x=0;x<4;x++)
                    {
                        if(currentBrick[y,x]==1)
                        {
                            Background[y + currentY, x + currentX] = currentBrick[y,x];
                        }
                    }
                }
                CalculateScore();
                //前一个方块到底了才能产生新的方块
                CreateBricks();
                DrawNextBrick();
            }
            //绘制方块
            DrawCurrentBrick();
        }

        //旋转方块
        private void RotateBrick()
        {
            int tempBrickDirec = (currentBrickDirec + 1) % 4;
            int[,] tempBrick = new int[4, 4];
            for(int y=0;y<4;y++)
            {
                for(int x=0;x<4;x++)
                {
                    tempBrick[y, x] = Bricks[currentBrickNum, currentBrickDirec, y, x];
                    if(tempBrick[y,x]==1&&(currentY+y+1)>20&&(currentX+x+1)>14)
                    {
                        return;
                    }
                    if(tempBrick[y,x]==1&&Background[currentY+y,currentX+x]==1)
                    {
                        return;
                    }
                }
            }

            currentBrick = tempBrick;
            currentBrickDirec = (currentBrickDirec + 1) % 4;
        }

        //检测方块是否可以下落
        private bool CheckFallBrick()
        {
            for(int y=0;y<4;y++)
            {
                for(int x=0;x<4;x++)
                {
                    if(currentBrick[y,x]==1)
                    {
                        //方块已经下落到底，不能下落
                        if((currentY+y+1)>=20)
                        {
                            return false;
                        }
                        //下方有别的方块，不能下落
                        if(Background[y+currentY+1,x+currentX]==1)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }

        //检测方块是否可以左移
        private bool CheckLeftBrick()
        {
            for(int y=0;y<4;y++)
            {
                for(int x=0;x<4;x++)
                {
                    if(currentBrick[y,x]==1)
                    {
                        //左移到边界，不能移动
                        if(x+currentX-1<0)
                        {
                            return false;
                        }
                        //左边有方块，不能移动
                        if(Background[y+currentY,x+currentX-1]==1)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }

        //检测方块是否可以右移
        private bool CheckRightBrick()
        {
            for(int y=0;y<4;y++)
            {
                for(int x=0;x<4;x++)
                {
                    if(currentBrick[y,x]==1)
                    {
                        //右移到边界，不能移动
                        if(x+currentX+1>=14)
                        {
                            return false;
                        }
                        //右边有方块，不能移动
                        if(Background[y+currentY,x+currentX+1]==1)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        
        //重新开始
        private void button1_Click(object sender, EventArgs e)
        {
            //初始化背景数组
            for (int y = 0; y < 20; y++)
            {
                for (int x = 0; x < 14; x++)
                {
                    Background[y, x] = 0;
                }
            }
            timer1.Interval = 1000;

            //生成第一个方块的序号和方向
            nextBrickNum = random.Next(0, 4);
            nextBrickDirec = random.Next(0, 4);

            CreateBricks();
            DrawCurrentBrick();       //绘制方块
            DrawNextBrick();          //绘制下一个方块
            this.panel1.Focus();      //将窗口变成输入焦点

            PlayMusic();
        }

        //暂停游戏
        private void button2_Click(object sender, EventArgs e)
        {
            if(button2.Text=="暂停游戏")
            {
                button2.Text = "开始游戏";
                timer1.Stop();
            }
            else
            {
                button2.Text = "暂停游戏";
                timer1.Start();
            }
        }

        //画出下一个方块，预览下一个方块
        private void DrawNextBrick()
        {
            Graphics g = this.panel2.CreateGraphics();
            g.Clear(this.panel2.BackColor);     //清除之前的图形
            for (int y=0; y<4; y++)
            {
                for (int x=0; x<4; x++)
                {
                    //j为横坐标,i为纵坐标
                    if (Bricks[nextBrickNum, nextBrickDirec, y, x] == 1)
                    {
                        g.FillRectangle(new SolidBrush(Color.DimGray), x * 20, y * 20, 20, 20);
                        g.DrawRectangle(new Pen(Color.Gainsboro, 1), x * 20, y * 20, 20, 20);
                    }
                }
            }
        }

        //计算得分,消去整行方块
        private void CalculateScore()
        {
            for (int y=19; y>=0; y--)
            {
                bool isFull = true;
                for (int x=13; x>=0; x--)
                {
                    //若一行当中有某个单元没有方块，则这一行不能消去
                    if (Background[y,x] == 0)
                    {
                        isFull = false;
                        break;
                    }
                }
                if (isFull)
                {
                    //增加得分  
                    score = score + 10;
                    for (int y1=y; y1>0; y1--)      //y1>0，消到第二行，第一行肯定没有方块
                    {
                        //消去一行后把这一行上面的所有方块向下移一行
                        for (int x1=0; x1<14; x1++)
                        {
                            Background[y1,x1] = Background[y1-1,x1];
                        }
                    }
                    //纵坐标为消去的这一行 继续判断
                    y++;    
                    label1.Text = "游戏得分： " + score.ToString();
                }
            }
        }

        //键盘响应事件
        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (this.button2.Text.Equals("开始游戏"))
            {
                //暂停的时候不响应键盘
                return;
            }

            else if (e.KeyValue==38)
            {
                //↑键按下
                //旋转方块
                RotateBrick();
                DrawCurrentBrick();
            }
            else if (e.KeyValue==37)
            {
                //←键按下
                //方块往左边移动
                if (CheckLeftBrick())
                {
                    currentX--;
                }
                DrawCurrentBrick();
            }
            else if (e.KeyValue==39)
            {
                //→键按下
                //方块向右移动
                if (CheckRightBrick())
                {
                    currentX++;
                }
                DrawCurrentBrick();
            }
            else if (e.KeyValue==40)
            {
                //↓键按下
                //方块加速下落
                this.timer1.Interval = 20;
            }
        }

        //覆盖默认的系统键处理方式，
        //遇到方向键，则直接返回，
        //系统不处理，这样键值就会被传递到窗体，触发keydown事件
        protected override bool ProcessDialogKey(Keys keyData)
        {
            if (keyData == Keys.Up || keyData == Keys.Down ||
            keyData == Keys.Left || keyData == Keys.Right)
                return false;
            else
                return base.ProcessDialogKey(keyData);
        }

        private void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            if(e.KeyCode==Keys.Down)
            {
                this.timer1.Interval = 1000;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            FallBrick();
        }

        //播放音乐
        private void PlayMusic()
        {
            System.Media.SoundPlayer sp = new System.Media.SoundPlayer();
            sp.SoundLocation = @".\Sound.wav";
            if (System.IO.File.Exists(@".\Sound.wav")) sp.PlayLooping();
        }
          
        private void 简单ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            timer1.Interval = 1000;
        }

        private void 一般ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            timer1.Interval = 400;
        }

        private void 困难ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            timer1.Interval = 200;
        }

		private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
		{
            panel3.Visible = true;
		}

		private void button3_Click(object sender, EventArgs e)
		{
            panel3.Visible = false;
		}

	}
}
